#pragma once
#include "core_headers.hpp"
#include "Channel.hpp"

#define MAX_EPOLL_EVENTS_DEFAULT 1024
class Poller
{
public:
	Poller()
	{
		_epfd = ::epoll_create(MAX_EPOLL_EVENTS_DEFAULT);
		if (_epfd < 0)
		{
			DEL_LOG("epoll_create error,%d,%s", errno, strerror(errno));
			return;
		}
	}
	~Poller()
	{
		if (_epfd != -1)
		{
			::close(_epfd);
			_epfd = -1;
		}
	}
	// 事件添加修改
	void UpdateEvents(Channel *channel)
	{
		if (!HashChannel(channel))
		{
			// 不存在则添加
			int fd = channel->Fd();
			_channels.insert(std::make_pair(channel->Fd(), channel));
			Update(channel, EPOLL_CTL_ADD);
			return;
		}
		// 存在则修改
		Update(channel, EPOLL_CTL_MOD);
	}
	// 事件移除
	void RemoveEvents(Channel *channel)
	{
		auto it = _channels.find(channel->Fd());
		if (it != _channels.end())
		{
			// 找到，从hash移除
			_channels.erase(channel->Fd());
		}
		// 然后把需要监控的事件移除
		Update(channel, EPOLL_CTL_DEL);
	}
	// 开始监控事件,
	void OpenPoll(std::vector<Channel *> *channel) // 遵循 * 表示输出参数的约定可以使代码更清晰，特别是对大型项目或多人协作项目。这种风格被 Google C++ 风格指南等广泛采用。
	{
		int ret = ::epoll_wait(_epfd, _evs, MAX_EPOLL_EVENTS_DEFAULT, -1);
		if (ret < 0)
		{
			if (errno == EINTR)
			{
				DEL_LOG("被信号中断,%d,%s", errno, strerror(errno));
				return;
			}
			DEL_LOG("epoll_wait errro,%d,%s", errno, strerror(errno));
			return;
		}
		// 根据_evs就绪的事件,设置实际就绪的事件revent，返回活跃链接调用对应的事件回调函数
		for (int i = 0; i < ret; i++)
		{
			auto it = _channels.find(_evs[i].data.fd);
			if (it == _channels.end())
			{
				continue;
			}
			it->second->SetRevent(_evs[i].events);
			channel->push_back(it->second);
		}
	}

private:
	// 对epoll实际添加修改移除事件
	void Update(Channel *channel, int op)
	{
		int fd = channel->Fd();
		struct epoll_event ev;
		ev.data.fd = channel->Fd();
		ev.events = channel->Events();
		int ret = ::epoll_ctl(_epfd, op, fd, &ev);
		if (ret < 0)
		{
			ERR_LOG("epoll_ctl error,%d,%s", errno, strerror(errno));
			return;
		}
	}
	// 事件是否存在
	bool HashChannel(Channel *channel)
	{
		auto it = _channels.find(channel->Fd());
		if (it == _channels.end())
		{
			// 没找到
			return false;
		}
		return true;
	}

private:
	int _epfd = -1;
	struct epoll_event _evs[MAX_EPOLL_EVENTS_DEFAULT];
	std::unordered_map<int, Channel *> _channels; // 把需要监控的描述符添加进来，事件触发时的快速查找，，并设置就绪事件
};

